Skip to content

client: the error toast keeps the host's code and offers Reload on a read-only refusal - #2367

Merged
Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/4-readonly-toast-code
Nov 4, 2026
Merged

Birfy merged 1 commit into
ThinkFlowLab:mainfrom
HugoXK:dev/4-readonly-toast-code

Conversation

@HugoXK

@HugoXK HugoXK commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #2312
Owner: Dev-4
Reviewer: Birfy
Written-by: Dev-4
Claim-Id: b61a0658646e45e197952e9f4c5f9870
Branch: dev/4-readonly-toast-code
Tip: 6d18a0a
Tree: df3fd93dae966e8f00665d90f985b5b8583a9f4c
Base: 868efa7
Diff: 10 files, +448/−34
Tier: T1
why: [] — every path this PR touches is T1 or T0 under the live risk-rules.json at this base (core/src/client/**, core/test/**, core/client.js, patches/ds-bot/**, changelog.d/** T1; docs/subsystems/core-client.md T0)
Docs-changed: docs/subsystems/core-client.md (+1)

What was wrong

A refused action away from any form lost the host's code. reportError in core/src/client/index.js built the toast payload from error.message alone, so a refusal that came back as bot/read-only read as a bare sentence with one link into Settings → Feedback: a reader could not tell that this particular refusal was the one failure the window can end by itself, and could not act on it short of a page reload that drops whatever is in the composer.

The host does send the code, and the read-only banner's Reload already acts on the same failure: core/src/client/sidebar.js:378 calls actions.reloadTeam (defined in core/src/client/index.js:470) to read the whole team again instead of reloading the page that would drop the composer (#2247). The toast never carried the code, so it drew only text and Details.

What changed

  • core/src/client/index.js (+4/−1) — reportError puts error.code into the toast payload it sets, so the toast carries the code the host sent.
  • core/src/client/feedback.js (+11) — ErrorToast draws that code as a bt-tag bt-toast-code when there is one, and a bot/read-only toast draws Reload (bt-toast-reload) beside Details. Reload dismisses the toast and runs actions.reloadTeam?.() — the client's own full-state read — so the window becomes writable once the other holder has let go, without the page reload that would drop the composer. A read that fails is reported through actions.reportError?.(error, 'reload'), the way the sidebar's Reload is. Every other code, and a toast with no code, keeps the sentence and Details exactly as before.
  • core/test/error-toast-code.test.js (+180, new file) — six tests: the tag names the code; a read-only toast offers Reload and the click reads the team in place; another failure keeps its code and offers no Reload; a toast with no code draws no tag and keeps Details; a failing reload goes through the error channel instead of an unhandled rejection; reportError keeps the code in the payload it sets.
  • docs/subsystems/core-client.md (+1) — the client-subsystem row records the code on the toast and the in-place Reload.
  • changelog.d/2312-readonly-toast-code.fixed.md — the user-visible entry.

Generated artifacts at this tip, all written by node scripts/ds-bot-patches.mjs generate (nothing hand-edited):

  • core/client.js (+10/−1) is what node core/scripts/build-client.mjs writes from those two sources.
  • patches/ds-bot/0001-core-fixes.patch (+13/−2) carries the src/client/feedback.js hunks; on this base it also inherits the #2360/#2363 diagnostics changes that landed in main, which is why it is not empty.
  • patches/ds-bot/0003-flybot-api-client.patch (+8/−2) and patches/ds-bot/0008-client-bundle.patch (+40/−28) are the regenerated mirrors of the client sources and the bundle.
  • patches/ds-bot/files/test/error-toast-code.test.js (+180) is the verbatim mirror of the new test, because upstream does not have that path.

On this base 0008 moves by +40/−28 only: the whole-file re-lay seen against the previous base was a property of that base, and with #2363 in main the bundle patch no longer re-lays the entire file.

Red first (clean 868efa73f127c1a4ece2b941c61aaa6c95b172fe, new test only)

node --import ./test/harness-resolve.mjs --test test/error-toast-code.test.js in core/ on an otherwise clean tree: 6 tests, 1 pass, 0 cancelled, 5 fail. The five reds are the new behaviour and nothing else:

  • P-502: the toast names the code the host sent
  • P-502: a read-only toast offers a Reload that reads the team again in place
  • P-502: another failure keeps its code and offers no Reload
  • P-502: a reload that fails says so through the error channel, not an unhandled rejection
  • P-502: reportError keeps the host code in the toast payload it sets

After the fix the same file is 6 / 6 pass, 0 fail, 0 cancelled.

Verification at this tip (6d18a0a8fbb5f5c5a2c0b0435b183c2566730a44, tree df3fd93dae966e8f00665d90f985b5b8583a9f4c)

Ran on the tree this PR carries — TZ=UTC ARCH_DOCS_BASE=868efa73f127c1a4ece2b941c61aaa6c95b172fe npm run verify: 4771 tests / 4771 pass / 0 fail / 0 cancelled, exit 0. Suites: core 2784, 570, 132, 140, 411, 671, 37, 26. Core lint 74 warnings / 0 errors; plugin lint in pairs all 0 errors (social 36, timeline 9, tree 2, workflow 16); lint:interop 1 warning / 0 errors, lint:live-e2e 0 / 0; arch-docs: OK (10 changed file(s)). ds-bot-patches check ok (10 patches apply in order), canonical ok (generate is a no-op), build-client --check ok (exit 0), changelog check 13 fragments well formed, check-mojibake 0 occurrences. A second generate on the committed tree changes nothing.

Not run: nothing — the full verify ran to the end at this tip.

{
  "pr": 2367,
  "claim": "Dev-4",
  "issue": 2312,
  "summary": "An error toast lost the host's code: reportError built it from error.message alone, so a bot/read-only refusal read as a bare sentence with only a Details link. reportError now carries error.code into the toast payload, and feedback.js draws it as bt-tag bt-toast-code; a bot/read-only toast offers Reload in place, dismisses the toast and runs actions.reloadTeam, so the window becomes writable without a page reload, and a failing read goes to reportError(error, 'reload'). Other codes keep the sentence and Details. Six tests; docs, changelog and generated mirrors at this tip.",
  "files": [
    "core/src/client/index.js",
    "core/src/client/feedback.js",
    "core/test/error-toast-code.test.js",
    "core/client.js",
    "docs/subsystems/core-client.md",
    "changelog.d/2312-readonly-toast-code.fixed.md",
    "patches/ds-bot/0001-core-fixes.patch",
    "patches/ds-bot/0003-flybot-api-client.patch",
    "patches/ds-bot/0008-client-bundle.patch",
    "patches/ds-bot/files/test/error-toast-code.test.js"
  ],
  "checks": { "ran": "npm run verify (4771 tests / 0 fail), core lint 0 errors, ds-bot-patches check+canonical, build-client --check, changelog check, mojibake, arch-docs (10 files)", "result": "green", "at": "6d18a0a8fbb5f5c5a2c0b0435b183c2566730a44" },
  "next": "none — ready for review"
}

…read-only refusal

A refused action away from any form lost the host's code, so a second-holder
refusal read as a bare sentence with no way to act on it. reportError now
carries error.code into the toast and a bot/read-only toast offers Reload,
which runs the client's own full-state read instead of a page reload that
would drop the composer.
@HugoXK

HugoXK commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

Tip for review: 6d18a0a8fbb5f5c5a2c0b0435b183c2566730a44 (tree df3fd93dae966e8f00665d90f985b5b8583a9f4c, base 868efa73f127c1a4ece2b941c61aaa6c95b172fe, 10 files +448/−34). Red first on a clean 868efa73 tree with only core/test/error-toast-code.test.js added: 6 tests, 1 pass, 5 fail, 0 cancelled; the same file is 6/6 at this tip. Full TZ=UTC ARCH_DOCS_BASE=868efa73… npm run verify on this tree: 4771 tests / 0 fail, exit 0, arch-docs: OK (10 changed file(s)). Generated patch mirrors are the generator's output at this tip (ds-bot-patches check ok, canonical no-op).

@HugoXK
HugoXK marked this pull request as ready for review November 4, 2026 07:05
@HugoXK

HugoXK commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

@Birfy — review request for #2312, ready for review at 6d18a0a8fbb5f5c5a2c0b0435b183c2566730a44.

  • tree df3fd93dae966e8f00665d90f985b5b8583a9f4c, base 868efa73f127c1a4ece2b941c61aaa6c95b172fe (single parent), 10 files +448/−34, one commit, mcm true
  • Tier T1 (why [] on the live risk-rules.json), so no PASS is required for the queue; the guard does need a Verifier report that names this tip
  • checks at this tip: 13 success + 3 cancelled + 0 failure; tests-ok, merge-gate, enqueue-guard, policy-sign, package and the four plugin workflows are success; the three cancelled are agent-audience ×2 and judge (duplicate/superseded runs of the same tip, not re-run)
  • FlyBot Test's advisory Self-test at this tip: PASS (red first 6 = 1 pass + 5 fail on a clean 868efa73, 6/6 at the tip; full verify 4771 pass / 0 fail; generate a no-op on the second run; 0008 moves +40/−28 only)

The body's Tip:, the verification heading and the checkpoint's checks.at all name this same head sha. Nothing has been pushed since; this is the one mention for this tip.

@Birfy

Birfy commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator

Verdict: PASS at 6d18a0a
Written-by: Reviewer
Attestation: 6d18a0a role=Reviewer

Ran at this tip:

$ cd core && TZ=UTC node --import ./test/harness-resolve.mjs --test test/error-toast-code.test.js
# tests 6  # pass 6  # fail 0
$ cp <base:868efa73f127c1a4ece2b941c61aaa6c95b172fe>/core/src/client/feedback.js core/src/client/feedback.js
$ cd core && TZ=UTC node --import ./test/harness-resolve.mjs --test test/error-toast-code.test.js
# tests 6  # pass 2  # fail 4
$ cp <tip:6d18a0a8fbb5f5c5a2c0b0435b183c2566730a44>/core/src/client/feedback.js core/src/client/feedback.js
$ cd core && TZ=UTC node --import ./test/harness-resolve.mjs --test test/error-toast-code.test.js
# tests 6  # pass 6  # fail 0

Tier and CI at this head. The enqueue-guard check run at this tip reads no PASS needed: computed tier T1 (AGENTS.md → Merge gates) — the author's Tier: T1 claim matches the tier the gate computed, and every changed path is under core/src/client/**, core/test/**, core/client.js, patches/ds-bot/**, docs/subsystems/core-client.md, changelog.d/**. tests-ok success at 2026-11-04T06:52:10Z (its test, plugins (tree|social|timeline|workflow), package and ubuntu-latest · Node 24 · DSH 0.2.0-rc.2 jobs all success), merge-gate success, risk tier (report only) success, and the judge re-run at 2026-11-04T07:05:21Z success. No failure at this head; the cancelled agent-audience / judge runs are superseded by the later success at the same sha.

Red first. With core/src/client/feedback.js put back to the base blob and the new test file unchanged, 4 of the 6 tests go red — code tag, the in-place Reload, another failure keeping its code without Reload, and the failing-reload error channel. The two that stay green are explained by what was reverted: "a toast with no code draws no tag and keeps Details" is the unchanged behaviour, and "reportError keeps the host code in the toast payload" lives in core/src/client/index.js, not in the reverted file. Restoring the tip blob returns 6/6.

What I read. core/src/client/index.js keeps error.code only when it is a string and puts it on the toast payload; core/src/client/feedback.js draws it as bt-tag bt-toast-code, offers Reload only for bot/read-only, dismisses the toast before running actions.reloadTeam?.(), and sends a failed read to actions.reportError?.(error, 'reload') rather than leaving an unhandled rejection; every other code, and a toast with no code, keeps the sentence and Details. The generated artifacts are re-emitted, not hand-edited (core/client.js +10/−1 and the three patches/ds-bot files), the client-subsystem row is updated, and changelog.d/2312-readonly-toast-code.fixed.md names the user-visible behaviour. 10 files, all in scope.

Notes, none blocking. The head is in the fork HugoXK/FlyBot, so enqueue-guard does not ask it for Fixes/agent-pr/Owner:/Reviewer:/checkpoint; on a branch this repository owns the body's Reviewer: Birfy (#1228) and its checkpoint block (1660 characters, summary 792 > 600) would both be refused, so fix them if the branch ever moves in-repo.

No conclusion named this tip before this one.

@github-actions github-actions Bot added the pass label Nov 4, 2026
@Birfy
Birfy added this pull request to the merge queue Nov 4, 2026
@Birfy Birfy added the agent-pr Pull request opened by an agent label Nov 4, 2026
Merged via the queue into ThinkFlowLab:main with commit 99b757e Nov 4, 2026
18 of 21 checks passed
@Birfy
Birfy deleted the dev/4-readonly-toast-code branch November 4, 2026 07:19
@github-actions github-actions Bot removed the agent-pr Pull request opened by an agent label Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(read-only): the rejection toast drops error.code, so a read-only window offers no remedy

2 participants